namespace Angelus.Oracle.Entity.OracleClient.OracleGen
{
    using System;
    using System.Data.Common;
    using System.Diagnostics;
    using Common.Entity;

    /// <summary>
    /// Description of OracleServerRequirements.
    /// </summary>
    internal class OracleServerRequirements
    {
        #region Constants

        internal const string OracleServer = "ORA";
        internal const string OracleServer10g = "Ora10g";
        internal const string OracleServer11g = "Ora11g";
        internal const string OracleServer92 = "Ora92";

        #endregion

        #region Fields

        private OracleVersion _version;

        #endregion

        #region Constructors

        /// <summary>
        /// 
        /// </summary>
        /// <param name="connection"></param>
        public OracleServerRequirements(DbConnection connection)
        {
            this.BuildUp(connection);
        }

        #endregion

        #region Properties

        /// <summary>
        /// 
        /// </summary>
        public OracleVersion OracleServerVersion
        {
            get { return this._version; }
        }

        #endregion

        #region Requirements Implementation

        /// <summary>
        /// 
        /// </summary>
        /// <param name="version"></param>
        /// <returns></returns>
        internal static string GetOracleServerVersion(OracleVersion version)
        {
            switch (version)
            {
                case OracleVersion.Oracle92:
                    return "Ora92";
                case OracleVersion.Oracle10g:
                    return "Ora10g";
                case OracleVersion.Oracle11g:
                    return "Ora11g";
                default:
                    throw Error.ProviderNotSupported(string.Empty);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public bool ValidateOracleServerVersion()
        {
            return ((OracleVersion.Oracle10g == this._version) ||
                    (OracleVersion.Oracle11g == this._version) ||
                    (OracleVersion.Oracle92 == this._version));
        }

        #endregion

        #region Private Implementation

        /// <summary>
        /// 
        /// </summary>
        /// <param name="connection"></param>
        private void BuildUp(DbConnection connection)
        {
            var serverVersion = new StoreVersion(connection);
            Debug.Assert(null != serverVersion);
            Version oracleVersion = ParseOracleServerVersion(serverVersion.Version);
            this._version = ParseOracleVersion(oracleVersion);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="s"></param>
        /// <param name="pos"></param>
        /// <returns></returns>
        private static int TryParseInt(string s, ref int pos)
        {
            int startIndex = pos;
            int length = s.Length;
            while ((pos < length) && char.IsDigit(s[pos]))
            {
                pos++;
            }
            if (pos == startIndex)
            {
                return 0;
            }
            return ParseIntWith0(s.Substring(startIndex, pos - startIndex));
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="s"></param>
        /// <returns></returns>
        private static int ParseIntWith0(string s)
        {
            int startIndex = 0;
            while ((startIndex < s.Length) && (s[startIndex] == '0'))
            {
                startIndex++;
            }
            if (startIndex > 0)
            {
                s = s.Substring(startIndex);
            }
            if (!(s == "") && !(s == "0"))
            {
                return int.Parse(s);
            }
            return 0;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="version"></param>
        /// <returns></returns>
        private static Version ParseOracleServerVersion(string version)
        {
            int index = version.IndexOf('.');
            if (index == -1)
            {
                throw new InvalidOperationException("");
            }
            index--;
            while ((index >= 0) && char.IsDigit(version[index]))
            {
                index--;
            }
            index++;
            int major = TryParseInt(version, ref index);
            index++;
            int minor = TryParseInt(version, ref index);
            index++;
            int revision = TryParseInt(version, ref index);
            index++;
            int buidlNumber = TryParseInt(version, ref index);
            return
                new Version(major.ToString("00") + "." + minor.ToString("00") + "." + revision.ToString("00") + "." +
                            buidlNumber.ToString("00"));
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="version"></param>
        /// <returns></returns>
        private static OracleVersion ParseOracleVersion(Version version)
        {
            switch (version.Major)
            {
                case 8:
                    return OracleVersion.Oracle8i;
                case 9:
                    if (version.Minor == 2)
                    {
                        return OracleVersion.Oracle92;
                    }
                    return OracleVersion.Oracle9i;
                case 10:
                    return OracleVersion.Oracle10g;
                case 11:
                    return OracleVersion.Oracle11g;
                default:
                    throw new ArgumentException(Strings.UnableToDetermineStoreVersion);
            }
        }

        #endregion
    }
}